﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLite.Mini.Context;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
using System.Diagnostics;
using NLite.Threading;
using NLite.Mini.Lifestyle;
using System.Collections;
using NLite.Collections;

namespace NLite.Internal
{
    class Tracker
    {
        const string key = "ComponentActivator.Traker";
        public static void Track(IPreCreationContext ctx)
        {
            var trakeItem = ctx.Component.Implementation == null ? ctx.Component.Id : ctx.Component.Implementation.FullName;

            var o = CallContext.GetData(key) as StringBuilder;
            if (o == null)
            {
                o = new StringBuilder();
                o.Append(trakeItem);
                CallContext.SetData(key, o);
            }
            else
                o.Append("->").Append(trakeItem);

        }

        public static void Clear()
        {
            CallContext.SetData(key, null);
        }
        public static string CallStack
        {
            get
            {
                return (CallContext.GetData(key) as StringBuilder).ToString();
            }
        }
    }

    class Property
    {
        public readonly PropertyInfo Name;
        public readonly object Owner;

        public Property(PropertyInfo name, object owner)
        {
            Name = name;
            Owner = owner;
        }
    }

    class TypeDeepCalculator
    {
        public int Deep
        {
            get
            {
                return deep == 1 ? 0 : deep - 2;
            }
        }

        private int deep = 0;
        public bool Calculate(Type parentType, Type type)
        {
            if (type == null)
                return false;

            deep = deep + 1;
            if (parentType.IsSubclassOf(type))
                return true;

            if (parentType.IsInterface)
                return type.GetInterface(parentType.Name) != null;

            return Calculate(parentType, type.BaseType);
        }
    }

    class LocalDataContext : IDataContext
    {
        [ThreadStatic]
        private static HashtableDataCollection _localData;
        private static readonly object LocalDataHashtableKey = new object();

        public IDataCollection Data
        {
            get
            {
                if (!NLiteEnvironment.IsWeb)
                {
                    if (_localData == null)
                        _localData = new HashtableDataCollection();
                    return _localData;
                }
                else
                {
                    var web_hashtable = HttpContextWrapper.Items[LocalDataHashtableKey] as HashtableDataCollection;
                    if (web_hashtable == null)
                    {
                        web_hashtable = new HashtableDataCollection();
                        HttpContextWrapper.Items[LocalDataHashtableKey] = web_hashtable;
                    }
                    return web_hashtable;
                }
            }
        }
    }

    [DebuggerDisplay("ThreadIndex={ThreadIndex}, From={From},To={To}")]
    class TaskItem
    {
        public Barrier Barrier;
        public int ThreadIndex;
        public int From;
        public int To;
        public Delegate Body;

        public virtual void Run()
        {
            var m = From;
            var n = To;

            try
            {
                for (; m <= n; m++)
                {
                    var o = Body.DynamicInvoke(m);
                }
            }
            finally
            {
            }

            Barrier.Await();
        }

    }

    class TaskItemAction : TaskItem
    {

        public Func<int, bool> Body;

        public void Run()
        {
            var m = From;
            var n = To;

            try
            {
                for (; m <= n; m++)
                    Body(m);
            }
            finally
            {
            }

            Barrier.Await();
        }

    }

    class TaskItemFunc : TaskItem
    {
       
        public Func<int,bool> Body;

        public void Run()
        {
            var m = From;
            var n = To;

            try
            {
                for (; m <= n; m++)
                {
                    if (!Body(m))
                    {
                        break;
                    }
                }
            }
            finally
            {
            }

            Barrier.Await();
        }

    }

    [Serializable]
    class Node<V>
    {
        public Node<V> Next;
        public V Value;
    }


    [Serializable]
    class ComponentPair
    {
        public IComponentInfo Component { get; internal set; }
        public ILifestyleManager LifestyleManager { get; internal set; }

        public ComponentPair(IComponentInfo info, ILifestyleManager lifestyleManager)
        {
            Component = info;
            LifestyleManager = lifestyleManager;
        }
    }

    struct EmptyDisposeAction : IDisposable
    {
        public void Dispose() { }
    }

    struct ActionDisposable : IDisposable
    {
        private Object Owner;
        private Action Action;
        public ActionDisposable(Action action)
        {
            Action = action;
            Owner = null;
        }

        public ActionDisposable(object owner, Action action)
        {
            Owner = owner;
            Action = action;
        }

        public void Dispose()
        {
            if (Owner != null)
                ServiceRegistry.Current.UnRegister(Owner.GetType());
            if (Action != null)
                Action();
        }
    }

    class LocalState : Hashtable, ICache, IApplication, ISession { }

    static class ComponentInfoExtensions
    {
        public static TMetadata GetMetadataView<TMetadata>(this IComponentInfo componentInfo)
        {
            return componentInfo.ExtendedProperties.GetMappingView<TMetadata>();
        }

        public static object GetMetadataView(this IComponentInfo componentInfo, Type viewType)
        {
            return componentInfo.ExtendedProperties.GetMappingView(viewType);
        }
    }

}
